/* eslint-disable operator-linebreak */
/* eslint-disable react/no-danger */
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useRef } from 'react';
import { Collapse } from 'antd';
import hljs from 'highlight.js';
import MarkdownIt from 'markdown-it';
import event from '@/assets/images/advanceReact/event.png';
import eventEmit from '@/assets/images/advanceReact/event_emit.png';

import 'highlight.js/styles/atom-one-light.css';
import './index.less';

const { Panel } = Collapse;
const mdParser = MarkdownIt({
  html: true,
  linkify: true,
  typographer: true,
  highlight(str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return hljs.highlight(lang, str).value;
      } catch (error) {
        console.log(error);
      }
    }
    return ''; // 使用额外的默认转义
  },
});

export default function SyntheticEvent() {
  return (
    <div className="advance-react-wrapper">
      <Collapse defaultActiveKey={['1', '2', '3', '4']}>
        <Panel header="1、DOM事件流" key="1">
          <p>
            W3C标准约定了一个事件的传播过程要经过以下3个阶段: 事件捕获阶段 -&gt; 目标阶段 -&gt;
            事件冒泡阶段
          </p>
          <p>
            事件委托:多个子元素的同一类型的监听逻辑合并到父元素上，通过一个监听函数来管理的行为。
          </p>
        </Panel>
        <Panel header="2、React事件系统" key="2">
          <p>
            当事件在具体的DOM节点上被触发后，最终都会冒泡到document上，document上所绑定的统一事件处理程序，会将事件分发到具体的组件实例。
          </p>
          <p>
            合成事件：在底层抹平了不同浏览器的差异在上层面向开发者暴露统一的、稳定的、与DOM原生事件相同的事件接口。
            虽然合成事件并不是原生DOM事件，但它保存了原生DOM事件的引用，可以通过e.nativeEvent得到。
          </p>
          <br />
          <h4>事件绑定</h4>
          <p>事件的绑定是在completeWork中完成的</p>
          <div style={{ display: 'flex', gap: 10 }}>
            <img src={event} alt="" width="30%" />
            <div>
              <code>legacyListenToTopLevelEvent</code>
              中的listenerMap中是当前document下已经监听事件的字典，通过判断该map是否含有topLevelType（如click），保证即便我们在React项目中多次调用了对同一个事件的监听
              也只会在document，上触发一次注册。
              <p>
                因为React最终注册到document上的并不是某一个DOM节点上对应的具体回调逻辑，
                而是一个统一的事件分发函数。
              </p>
              <p>
                listener是dispatchDiscreteEvent、dispatchUserBlockingUpdate、dispatchEvent中一个函数，区别在于对优先级处理不同，最终还是调用dispatchEvent这个统一的事件分发函数。
              </p>
            </div>
          </div>
          <h4>事件触发</h4>
          <p>它的本质是对dispatchEvent函数的调用</p>
          <div style={{ display: 'flex', gap: 10 }}>
            <img src={eventEmit} alt="" width="30%" />
            <div>
              <code>treverseTwoPhase(inst,fn,arg)收集函数</code>
              <ol>
                <li>
                  traverseTwoPhase会以当前节点(触发事件的目标节点)为起点
                  不断向上寻找tag===HostComponent的父节点，并将这些节点按顺序收集进path数组中。
                </li>
                <li>
                  模拟事件在捕获阶段的传播顺序，收集捕获阶段相关的节点实例与回调函数。path数组中子节点在前，祖先节点在后。
                  其实就是从父节点往下遍历子节点，直至遍历到目标节点的过程，
                  这个遍历顺序和事件在捕获阶段的传播顺序是一致的
                </li>
                <li>
                  模拟事件在冒泡阶段的传播顺序，收集冒泡阶段相关的节点实例与回调函数。traverseTwoPhase会从后往前遍历path数组
                  模拟事件的冒泡顺序，收集事件在捕获阶段对应的回调与实例。
                  <br />
                  正序遍历自然模拟的就是冒泡阶段的事件传播顺序,
                  若该节点上对应当前事件的冒泡回调不为空,
                  那么节点实例和事件回调同样会分别被收集到SyntheticEvent._dispatchInstances和SyntheticEvent._dispatchListeners中去
                </li>
              </ol>
            </div>
            <p>对React来说事件委托主要的作用，应该在于帮助React实现了对所有事件的中心化管控。</p>
          </div>
        </Panel>
      </Collapse>
    </div>
  );
}
